﻿using System.Data.SqlClient;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System;
using PropertyExpression.Common;

namespace PropertyExpression.DynamicQueryStaticChecking.Test
{
    public interface IParamManager<out T>
    {
        void AddAllFields();
        string Param<TProperty>(IPropertyExpressionProxy<T, TProperty> propertyExpressionProxy);
    }

    public static class ParamProviderExtensions
    {
        public static string Param<T, TProperty>(
            this IParamManager<T> it, Expression<Func<T, TProperty>> propertyExpression)
        {
            return it.Param(propertyExpression.ToPropertyExpressionProxy());
        }

        public static IParamManager<T> AsParamProvider<T>(this T it, SqlCommand sqlCommand)
        {
            return new ParamManager<T>(it, sqlCommand);
        }

        private class ParamManager<T> : IParamManager<T>
        {
            private readonly T parameters;
            private readonly SqlCommand sqlCommand;

            public ParamManager(T parameters, SqlCommand sqlCommand)
            {
                this.parameters = parameters;
                this.sqlCommand = sqlCommand;
            }

            public void AddAllFields()
            {
                foreach (var fieldInfo in typeof(T).GetFields())
                {
                    Param(fieldInfo);
                }
            }

            private string Param(FieldInfo fieldInfo)
            {
                var parameterName = fieldInfo.GetParameterName();
                sqlCommand.Parameters.AddWithValue(
                    parameterName,
                    fieldInfo.GetValue(parameters)
                    );
                return parameterName;
            }

            public string Param<TProperty>(IPropertyExpressionProxy<T, TProperty> propertyExpressionProxy)
            {
                return Param(propertyExpressionProxy.GetFieldInfo());
            }
        }

        internal static string GetParameterName(this FieldInfo fieldInfo)
        {
            return string.Format("@{0}", fieldInfo.Name);
        }
    }

    internal class StoredProceduresCreatingParamManager<T> : IParamManager<T>
    {
        private readonly StringBuilder stringBuilder;

        public StoredProceduresCreatingParamManager(StringBuilder stringBuilder)
        {
            this.stringBuilder = stringBuilder;
        }

        public void AddAllFields()
        {
            foreach (var fieldInfo in typeof(T).GetFields())
            {
                Param(fieldInfo);
            }
        }

        private string Param(FieldInfo fieldInfo)
        {
            var parameterName = fieldInfo.GetParameterName();
            stringBuilder.AppendFormat("{0} {1}", parameterName, fieldInfo.FieldType);
            stringBuilder.AppendLine();
            return parameterName;
        }

        public string Param<TProperty>(IPropertyExpressionProxy<T, TProperty> propertyExpressionProxy)
        {
            return Param(propertyExpressionProxy.GetFieldInfo());
        }
    }
}